package com.ybwh.springboot1.controller;

import com.ybwh.datasource.refreshable.spring.boot.RefreshableMasterSlaveDataSource;
import com.ybwh.datasource.refreshable.druid.DruidRefreshDataSource;
import com.ybwh.springboot1.common.Response;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author saytime
 * @since 2018-12-06
 */
@Controller
@RequestMapping("/")
public class IndexController implements ApplicationContextAware , EnvironmentAware {
	private static final String DB1_URL = "jdbc:mysql://127.0.0.1:3306/db_1?useSSL=false&characterEncoding=utf8&useUnicode=true&zeroDateTimeBehavior=convertToNull";
	private static final String DB2_URL = "jdbc:mysql://127.0.0.1:3306/db_2?useSSL=false&characterEncoding=utf8&useUnicode=true&zeroDateTimeBehavior=convertToNull";

	private ApplicationContext context;
	private Environment environment;

	@ResponseBody
	@RequestMapping("/index")
	public ModelAndView index() {
		ModelAndView mav = new ModelAndView("index");

		return mav;
	}

	@ResponseBody
	@RequestMapping("/changeDb")
	public Response<Object> changeDb(@RequestParam("db") String db) {

		try {

//			changeDruidDb(db);

			changeMasterslaveDb(db);

			return Response.successResp(null);
		}catch (Exception e){
			e.printStackTrace();
			return Response.failedResp(null);
		}
	}


	private void changeMasterslaveDb(String db) throws Exception {
		RefreshableMasterSlaveDataSource dataSource = (RefreshableMasterSlaveDataSource) context.getBean("dataSource");

		/**
		 * bean的属性会由配置中心客户端刷新，这里只是模拟刷新属性,实际项目中在配置中心回调事件中调用refresh即可
		 */
		String dbUrl = DB1_URL;
		if ("db_2".equals(db)) {
			dbUrl = DB2_URL;
		}


		//修改主从库链接配置
		AbstractEnvironment abstractEnvironment = (AbstractEnvironment) environment;


		PropertySource<?> target = null;

		for(PropertySource<?> ps : abstractEnvironment.getPropertySources()) {


			if(ps.getName().startsWith("applicationConfig")) {
				target  = ps;
				break;
			}

		}

		Properties pros = new Properties();
		pros.put("refreshable.sharding.jdbc.datasource.master.url",dbUrl);
		pros.put("refreshable.sharding.jdbc.datasource.slave0.url",dbUrl);

		Map map = (Map) target.getSource();
		map.putAll(pros);

		//更新所有bean @value注解的字段。
//		for(String beanName : context.getBeanDefinitionNames()) {
//			Object bean = context.getBean(beanName);
//			for(Field f : bean.getClass().getDeclaredFields()) {
//				Value valueAnno = f.getAnnotation(Value.class);
//				if(valueAnno==null) {
//					continue;
//				}
//				String key = valueAnno.value();
//				if(key==null) {
//					continue;
//				}
//				key = key.replace("${", "").replace("}", "");
//				key = key.split(":")[0];
//				if(map.containsKey(key)) {
//					f.setAccessible(true);
//					try {
//						f.set(bean, map.get(key));
//					} catch (Exception e) {
//						e.printStackTrace();
//					}
//				}
//			}
//		}

		dataSource.refresh();
	}


	private void changeDruidDb(String db) throws SQLException {
		DruidRefreshDataSource dataSource = context.getBean(DruidRefreshDataSource.class);

		/**
		 * bean的属性会由配置中心客户端刷新，这里只是模拟刷新属性,实际项目中在配置中心回调事件中调用refresh即可
		 */
		if ("db_1".equals(db)) {
			dataSource.getProperties().setUrl(DB1_URL);
		}

		if ("db_2".equals(db)) {
			dataSource.getProperties().setUrl(DB2_URL);
		}

		dataSource.refresh();
	}


	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		context = applicationContext;
	}

	@Override
	public final void setEnvironment(Environment environment) {
		this.environment= environment;
	}
}
